package com.rmv.ums.configuration;

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

import org.apache.log4j.Logger;

import com.rmv.ums.request.Request;
import com.rmv.ums.response.Response;

public class Configuration {

	private static final Logger logger = Logger.getLogger(Configuration.class);

	// constants
	public static final String REQUEST = "request";
	public static final String CONDITION = "condition";
	public static final String RESPONSE = "response";

	public static final String PLUGIN_GENERAL_CONFIGURATION = "config/plugin.properties";
	public static final String PLUGIN_REQUESTS_CONFIGURATION = "config/requests.xml";

	public static final String RESPONSE_UNKNOWN_REQUEST_ID_KEY = "response.unknown.request.id";
	public static final String DEFAULT_RESPONSE_BAD_CHECKS_ID_KEY = "response.default.bad.check.id";

	// singleton
	private static Configuration instance = null;

	protected Configuration() {
		// Exists only to defeat instantiation.
	}

	public static Configuration getInstance() {
		if (instance == null) {
			instance = new Configuration();
		}
		return instance;
	}

	// fields
	private Map configuration;
	private Set requests;
	private Map responses;
	private Response unknownRequestResponse;
	private Response badCheckDefaultResponse;

	// methods
	public void loadConfiguration(String configurationFile) {

		configuration = new Properties();

		// load all the plugin configuration files
		try {
			Enumeration configurationFiles = this.getClass().getClassLoader().getResources(PLUGIN_GENERAL_CONFIGURATION);
			while (configurationFiles.hasMoreElements()) {
				URL url = (URL) configurationFiles.nextElement();
				loadConfiguration(url);
				logger.info("loaded the configuration from:" + url.getPath());

			}
		} catch (IOException e) {
			throw new RuntimeException("error loading the plugin configuration files", e);
		}

		// load the main configuration file
		try {
			URL url = new File(configurationFile).toURL();
			loadConfiguration(url);
		} catch (MalformedURLException e) {
			throw new RuntimeException("error loading main configuration file", e);
		}

	}

	private void loadConfiguration(URL url) {
		ConfigurationLoader loader = new ConfigurationLoader(url);
		configuration.putAll(loader.getConfiguration());
	}

	public void loadRequests(String requestsFile) {

		requests = new HashSet();
		responses = new HashMap();

		// load all the plugin requests files
		try {
			Enumeration requestsFiles = this.getClass().getClassLoader().getResources(PLUGIN_REQUESTS_CONFIGURATION);
			while (requestsFiles.hasMoreElements()) {
				URL url = (URL) requestsFiles.nextElement();
				loadRequests(url);
				logger.info("loaded the configuration from:" + url.getPath());
			}
		} catch (IOException e) {
			throw new RuntimeException("error loading the plugin requests files", e);
		}

		// load the main requests file
		try {
			URL url = new File(requestsFile).toURL();
			loadRequests(url);
		} catch (MalformedURLException e) {
			throw new RuntimeException("error loading main requests file", e);
		}

		// Unknown Request response
		String idUknownRequestResponse = getConfigurationValue(Configuration.RESPONSE_UNKNOWN_REQUEST_ID_KEY);
		this.unknownRequestResponse = (Response) responses.get(idUknownRequestResponse);
		if (this.unknownRequestResponse == null) {
			throw new RuntimeException("not found UnknownRequest response:" + idUknownRequestResponse);
		}

		// Bad Checks default response
		String idBadChecksDefaultResponse = getConfigurationValue(Configuration.DEFAULT_RESPONSE_BAD_CHECKS_ID_KEY);
		this.badCheckDefaultResponse = (Response) responses.get(idBadChecksDefaultResponse);
		if (this.badCheckDefaultResponse == null) {
			throw new RuntimeException("not found badChecks default response:" + idBadChecksDefaultResponse);
		}

		// Checking requests
		for (Iterator iterator = requests.iterator(); iterator.hasNext();) {
			Request request = (Request) iterator.next();

			if (!request.postConfigure(responses)) {
				iterator.remove();
			}
		}

		if (logger.isDebugEnabled()) {
			dumpRequestsConfiguration();
			logger.debug("requests configured:" + requests.size());
		}

	}

	private void loadRequests(URL url) {
		RequestsLoader loader = new RequestsLoader(url);
		requests.addAll(loader.getRequests());
		responses.putAll(loader.getResponses());
	}

	public String getConfigurationValue(String key) {
		return (String) configuration.get(key);
	}

	public Set getRequests() {
		return requests;
	}

	public void setRequests(Set requests) {
		this.requests = requests;
	}

	public Response getUnknownRequestResponse() {
		return unknownRequestResponse;
	}

	public void setUnknownRequestResponse(Response unknownRequestResponse) {
		this.unknownRequestResponse = unknownRequestResponse;
	}

	public Response getBadCheckDefaultResponse() {
		return badCheckDefaultResponse;
	}

	public void setBadCheckDefaultResponse(Response badCheckDefaultResponse) {
		this.badCheckDefaultResponse = badCheckDefaultResponse;
	}

	private void dumpRequestsConfiguration() {
		logger.debug("--------------- configured requests -------------");
		for (Iterator iterator = requests.iterator(); iterator.hasNext();) {
			Request request = (Request) iterator.next();
			logger.debug(request);

		}
		logger.debug("--------------- special responses -------------");
		logger.debug(unknownRequestResponse);
		logger.debug(badCheckDefaultResponse);
		logger.debug("-----------------------------------------------");
	}

	// private void setFileWatchDog(String filename) {
	// FileWatchdog watchDog = new FileWatchdog(filename) {
	// protected void doOnChange() {
	// try {
	// internalLoad();
	// Configuration.getInstance().setRequests(requests);
	// } catch (Throwable e) {
	// logger.error("error reloading request configuration from file " + main +
	// " - using the old configuration");
	// }
	// }
	// };
	// watchdogs.add(watchDog);
	// if (logger.isDebugEnabled())
	// logger.debug("set watchdog for request configuration file:" + filename);
	// }

}
